package sunhang3.parse;

import android.content.Context;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.Surface;

import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.List;

public class ParseH264 {
    public static final int BYTE_SIZE = 1024 * 8;
    private String mAssetsFile;
    private Surface mSurface;
    private Context mContext;
    private NaluMgr mNaluMgr = new NaluMgr();

    public interface Finished {
        void onFinish();
    }

    public ParseH264(Context context, String assetsFile) {
        mContext = context;
        mAssetsFile = assetsFile;
    }

    public void bindSurface(Surface surface) {
        mSurface = surface;
    }

    public void startWork(Finished finished) {
        MediaCodec mediaCodec;
        try {
            mediaCodec = MediaCodec.createDecoderByType("video/avc");
            MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", 640, 480);
            mediaFormat.setInteger(MediaFormat.KEY_BITRATE_MODE, MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_CBR);
            mediaCodec.configure(mediaFormat, mSurface, null, 0);
        } catch (IOException e) {
            finished.onFinish();
            e.printStackTrace();
            return;
        }

        mediaCodec.start();

        ToSurface toSurfaceThread = new ToSurface(mediaCodec);
        toSurfaceThread.start();

        Parser parser = new Parser(mediaCodec, toSurfaceThread, finished);
        parser.start();
    }

    private void close(InputStream in) {
        if (in != null) {
            try {
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private class Parser extends Thread {
        MediaCodec mMediaCodec;
        Thread mToSurface;
        Finished mFinished;

        Parser(MediaCodec mediaCodec, Thread toSurface, Finished finished) {
            this.mMediaCodec = mediaCodec;
            this.mToSurface = toSurface;
            this.mFinished = finished;
        }

        @Override
        public void run() {
            ByteBuffer[] byteBuffers = mMediaCodec.getInputBuffers();
            InputStream in = null;
            try {
                in = mContext.getAssets().open(mAssetsFile);

                int len;
                byte[] buffer = new byte[BYTE_SIZE];
                while ((len = in.read(buffer)) != -1) {
                    List<byte[]> list = mNaluMgr.append(buffer, len);

                    for (byte[] byteArray : list) {
                        int inIndex = mMediaCodec.dequeueInputBuffer(10000);
                        // 填充到mediaCodec中
                        if (inIndex >= 0) {
                            ByteBuffer byteBuffer = byteBuffers[inIndex];
                            byteBuffer.clear();
                            byteBuffer.put(byteArray, 0, byteArray.length);
                            mMediaCodec.queueInputBuffer(inIndex, 0, byteArray.length, 0, 0);
                        }
                    }

                    try {
                        Thread.sleep(30);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        break;
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                close(in);
                mToSurface.interrupt();
                new Handler(Looper.getMainLooper()).post(new Runnable() {
                    @Override
                    public void run() {
                        mFinished.onFinish();
                    }
                });
            }
        }
    }

    private class ToSurface extends Thread {
        MediaCodec mMediaCodec;

        ToSurface(MediaCodec codec) {
            this.mMediaCodec = codec;
        }

        @Override
        public void run() {
            while (!isInterrupted()) {
                try {
                    Thread.sleep(30);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    break;
                }

                MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
                int outIndex = mMediaCodec.dequeueOutputBuffer(info, 10000);
                if (outIndex >= 0) {
                    mMediaCodec.releaseOutputBuffer(outIndex, true);
                } else {
//                    Log.e("sunhang3", "没有解码成功 " + outIndex);
                }
            }

            mMediaCodec.release();
            Log.i("sunhang3", "tosurface over");
        }
    }
}
